import pygame
import sys
import copy
import time

# 初始化pygame
pygame.init()
pygame.font.init()

# 确保中文能正常显示
font = pygame.font.SysFont(['SimHei', 'WenQuanYi Micro Hei', 'Heiti TC'], 36)
small_font = pygame.font.SysFont(['SimHei', 'WenQuanYi Micro Hei', 'Heiti TC'], 24)

# 游戏窗口设置
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("推箱子")

# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
BROWN = (139, 69, 19)  # 墙壁颜色
YELLOW = (255, 255, 0)  # 玩家颜色
GREEN = (0, 255, 0)  # 目标点颜色
BLUE = (0, 0, 255)  # 箱子颜色
DARK_GREEN = (0, 100, 0)  # 箱子在目标点上的颜色

# 游戏元素大小
CELL_SIZE = 50
GRID_MARGIN = 10


# 游戏状态
class GameState:
    PLAYING = 0
    LEVEL_COMPLETED = 1
    GAME_COMPLETED = 2


# 游戏类
class Game:
    def __init__(self):
        self.levels = self.load_levels()
        self.current_level = 0
        self.player_pos = None
        self.boxes = []
        self.targets = []
        self.walls = []
        self.moves = 0
        self.state = GameState.PLAYING
        self.history = []  # 用于撤销操作
        self.level_completed_time = 0  # 关卡完成时间
        self.load_level(self.current_level)

    def load_levels(self):
        # 简单的关卡定义
        levels = []

        # 第一关
        level1 = {
            'walls': [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0),
                      (0, 1), (7, 1),
                      (0, 2), (7, 2),
                      (0, 3), (7, 3),
                      (0, 4), (7, 4),
                      (0, 5), (7, 5),
                      (0, 6), (1, 6), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6), (7, 6)],
            'boxes': [(2, 3), (3, 4), (4, 3)],
            'targets': [(2, 2), (3, 2), (4, 2)],
            'player': (3, 5)
        }
        levels.append(level1)

        # 第二关
        level2 = {
            'walls': [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0), (9, 0),
                      (0, 1), (9, 1),
                      (0, 2), (9, 2),
                      (0, 3), (9, 3),
                      (0, 4), (9, 4),
                      (0, 5), (9, 5),
                      (0, 6), (1, 6), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6), (7, 6), (8, 6), (9, 6)],
            'boxes': [(2, 3), (3, 3), (4, 3), (5, 3)],
            'targets': [(2, 2), (3, 2), (4, 2), (5, 2)],
            'player': (3, 5)
        }
        levels.append(level2)

        # 第三关
        level3 = {
            'walls': [(0, 0), (1, 0), (2, 0), (3, 0), (4, 0), (5, 0), (6, 0), (7, 0),
                      (0, 1), (7, 1),
                      (0, 2), (3, 2), (4, 2), (7, 2),
                      (0, 3), (3, 3), (4, 3), (7, 3),
                      (0, 4), (3, 4), (4, 4), (7, 4),
                      (0, 5), (7, 5),
                      (0, 6), (1, 6), (2, 6), (3, 6), (4, 6), (5, 6), (6, 6), (7, 6)],
            'boxes': [(2, 3), (5, 3)],
            'targets': [(2, 5), (5, 5)],
            'player': (3, 1)
        }
        levels.append(level3)

        return levels

    def load_level(self, level_index):
        if 0 <= level_index < len(self.levels):
            level = self.levels[level_index]
            self.walls = level['walls']
            self.boxes = level['boxes']
            self.targets = level['targets']
            self.player_pos = level['player']
            self.moves = 0
            self.state = GameState.PLAYING
            self.history = []  # 清空历史记录

    def is_position_valid(self, pos):
        # 检查位置是否超出边界
        x, y = pos
        if x < 0 or y < 0 or x >= WIDTH // CELL_SIZE or y >= HEIGHT // CELL_SIZE:
            return False

        # 检查是否是墙壁
        if pos in self.walls:
            return False

        return True

    def is_box_at(self, pos):
        return pos in self.boxes

    def is_target_at(self, pos):
        return pos in self.targets

    def move_player(self, dx, dy):
        if self.state != GameState.PLAYING:
            return False

        # 保存当前状态用于撤销
        self.save_state()

        new_pos = (self.player_pos[0] + dx, self.player_pos[1] + dy)

        # 检查新位置是否有效
        if not self.is_position_valid(new_pos):
            return False

        # 检查是否有箱子
        if self.is_box_at(new_pos):
            # 计算箱子的新位置
            new_box_pos = (new_pos[0] + dx, new_pos[1] + dy)

            # 检查箱子的新位置是否有效且没有其他箱子
            if not self.is_position_valid(new_box_pos) or self.is_box_at(new_box_pos):
                return False

            # 移动箱子
            box_index = self.boxes.index(new_pos)
            self.boxes[box_index] = new_box_pos

        # 移动玩家
        self.player_pos = new_pos
        self.moves += 1

        # 检查是否完成关卡
        if self.check_level_completed():
            self.state = GameState.LEVEL_COMPLETED
            self.level_completed_time = time.time()

        return True

    def check_level_completed(self):
        # 检查所有箱子是否都在目标点上
        for box in self.boxes:
            if not self.is_target_at(box):
                return False
        return True

    def save_state(self):
        # 保存当前游戏状态
        state = {
            'player_pos': self.player_pos,
            'boxes': copy.deepcopy(self.boxes),
            'moves': self.moves
        }
        self.history.append(state)

    def undo_move(self):
        if len(self.history) > 0:
            state = self.history.pop()
            self.player_pos = state['player_pos']
            self.boxes = state['boxes']
            self.moves = state['moves']
            self.state = GameState.PLAYING
            return True
        return False

    def next_level(self):
        if self.current_level < len(self.levels) - 1:
            self.current_level += 1
            self.load_level(self.current_level)
            return True
        else:
            self.state = GameState.GAME_COMPLETED
            return False

    def restart_level(self):
        self.load_level(self.current_level)

    def update(self):
        # 自动下一关逻辑
        if self.state == GameState.LEVEL_COMPLETED and time.time() - self.level_completed_time > 2:
            if not self.next_level():
                self.state = GameState.GAME_COMPLETED

    def draw(self, screen):
        # 绘制背景
        screen.fill(GRAY)

        # 计算游戏区域偏移量，使其居中
        max_x = max(max(wall[0] for wall in self.walls),
                    max(box[0] for box in self.boxes),
                    self.player_pos[0])
        max_y = max(max(wall[1] for wall in self.walls),
                    max(box[1] for box in self.boxes),
                    self.player_pos[1])

        offset_x = (WIDTH - (max_x + 1) * CELL_SIZE) // 2
        offset_y = (HEIGHT - (max_y + 1) * CELL_SIZE) // 2

        # 绘制墙壁
        for wall in self.walls:
            x, y = wall
            pygame.draw.rect(screen, BROWN,
                             (offset_x + x * CELL_SIZE, offset_y + y * CELL_SIZE,
                              CELL_SIZE, CELL_SIZE))

        # 绘制目标点
        for target in self.targets:
            x, y = target
            pygame.draw.rect(screen, GREEN,
                             (offset_x + x * CELL_SIZE + 5, offset_y + y * CELL_SIZE + 5,
                              CELL_SIZE - 10, CELL_SIZE - 10))

        # 绘制箱子
        for box in self.boxes:
            x, y = box
            color = DARK_GREEN if self.is_target_at(box) else BLUE
            pygame.draw.rect(screen, color,
                             (offset_x + x * CELL_SIZE + 5, offset_y + y * CELL_SIZE + 5,
                              CELL_SIZE - 10, CELL_SIZE - 10))

        # 绘制玩家
        x, y = self.player_pos
        pygame.draw.circle(screen, YELLOW,
                           (offset_x + x * CELL_SIZE + CELL_SIZE // 2,
                            offset_y + y * CELL_SIZE + CELL_SIZE // 2),
                           CELL_SIZE // 2 - 5)

        # 绘制信息
        level_text = small_font.render(f"关卡: {self.current_level + 1}/{len(self.levels)}", True, BLACK)
        moves_text = small_font.render(f"步数: {self.moves}", True, BLACK)

        screen.blit(level_text, (20, 20))
        screen.blit(moves_text, (20, 50))

        # 绘制操作提示
        controls_text = small_font.render("方向键: 移动   R: 重置关卡   U: 撤销", True, BLACK)
        screen.blit(controls_text, (WIDTH // 2 - controls_text.get_width() // 2, HEIGHT - 30))

        # 绘制关卡完成信息
        if self.state == GameState.LEVEL_COMPLETED:
            message = f"完成关卡 {self.current_level + 1}!"
            message_text = font.render(message, True, BLACK)

            # 显示剩余时间
            remaining_time = max(0, 2 - (time.time() - self.level_completed_time))
            continue_text = small_font.render(f"自动进入下一关: {remaining_time:.1f}秒", True, BLACK)

            screen.blit(message_text, (WIDTH // 2 - message_text.get_width() // 2, HEIGHT // 2 - 50))
            screen.blit(continue_text, (WIDTH // 2 - continue_text.get_width() // 2, HEIGHT // 2 + 20))

        # 绘制游戏完成信息
        if self.state == GameState.GAME_COMPLETED:
            message = "恭喜你完成了所有关卡!"
            message_text = font.render(message, True, BLACK)
            restart_text = small_font.render("按R重新开始游戏", True, BLACK)

            screen.blit(message_text, (WIDTH // 2 - message_text.get_width() // 2, HEIGHT // 2 - 50))
            screen.blit(restart_text, (WIDTH // 2 - restart_text.get_width() // 2, HEIGHT // 2 + 20))


# 主函数
def main():
    clock = pygame.time.Clock()
    game = Game()

    running = True
    while running:
        clock.tick(60)

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_UP:
                    game.move_player(0, -1)
                elif event.key == pygame.K_DOWN:
                    game.move_player(0, 1)
                elif event.key == pygame.K_LEFT:
                    game.move_player(-1, 0)
                elif event.key == pygame.K_RIGHT:
                    game.move_player(1, 0)
                elif event.key == pygame.K_r:
                    game.restart_level()
                elif event.key == pygame.K_u:
                    game.undo_move()

        # 更新游戏状态
        game.update()

        # 绘制游戏
        game.draw(screen)

        # 更新显示
        pygame.display.flip()

    pygame.quit()
    sys.exit()


if __name__ == "__main__":
    main()